package async

import (
	"context"
	"fmt"
	"sync"
)

// 并发请求 当其中一个有结果时返回

type GroupFirstResult[T any] interface {
	Value() T
}

type groupFirstHandleFunc[T any] func(ctx context.Context) (GroupFirstResult[T], error)

type GroupFirst[T any] struct {
	Ctx         context.Context
	cancel      context.CancelFunc
	wg          sync.WaitGroup
	successChan chan struct{}
	result      GroupFirstResult[T]
}

func NewGroupFirst[T any]() *GroupFirst[T] {
	ctx, cancel := context.WithCancel(context.Background())
	return &GroupFirst[T]{Ctx: ctx, cancel: cancel, successChan: make(chan struct{})}
}

func (group *GroupFirst[T]) Add(handle groupFirstHandleFunc[T]) *GroupFirst[T] {
	group.wg.Add(1)
	go func() {
		defer group.wg.Done()

		go func() {
			res, err := handle(group.Ctx)
			if err != nil {
				return
			}

			group.successChan <- struct{}{}
			group.result = res
		}()

		select {
		case <-group.Ctx.Done():
			return
		case <-group.successChan:
			group.cancel()
		}
	}()
	return group
}

func (group *GroupFirst[T]) Wait() (GroupFirstResult[T], error) {
	group.wg.Wait()

	if group.result == nil {
		return nil, fmt.Errorf("can not get result from GroupFirst")
	}

	return group.result, nil
}
